Shiny Dashboards
shinydashboard

Colin Rundel

shinydashboard

is a package that enables the easy generation of bootstrap based dynamic Shiny dashboards.

The core of the package is a common dashboard layout and a number of specialized UI elements (static and reactive) for creating an attractive interface.


Dashboard basics

library(shiny)
library(shinydashboard)

shinyApp(
  ui = dashboardPage(
    dashboardHeader(
      title="shinydashboard"
    ),
    dashboardSidebar(),
    dashboardBody()
  ),
  server = function(input, output, session) {
  }
)

Dashboard header

This is a container for the title and any dropdownMenu()s

  • the latter are somewhat limited, support “messages”, “notifications”, “tasks” types

  • Dynamic menus can be generated using dropdownMenuOutput() and renderMenu() in the ui and server respectively.

Dashboard sidebar

This functions in the same way as the sidebarPanel() in sidebarLayout(), allowing for the inclusion of inputs and any other html content.

Alternatively, it can also function as a tabPanel() like menu.

  • instead of tabsetPanel() we use sidebarMenu(),

  • text and icons are assigned using menuItem()

  • the panels being activated are contained in the body and not the sidebar

    • their UI code goes under dashboardBody() using tabItems() and tabItem().

    • menuItem()s are connected to tabItems() via matching the tabName arguments.

Demo 07-1 - sidebarMenu()

demos/demo07-1.R

library(tidyverse)
library(shiny)
library(shinydashboard)

d = readr::read_csv(here::here("data/weather.csv"))

d_vars = d |>
  select(where(is.numeric)) |>
  names()


shinyApp(
  ui = dashboardPage(
    dashboardHeader(
      title="shinydashboard"
    ),
    dashboardSidebar(
      selectInput(
        "city", "Select a city",
        choices = c("Chicago", "Durham", "Sedona", "New York", "Los Angeles")
      ),
      selectInput(
        "var", "Select a variable",
        choices = d_vars, selected = "humidity"
      ),
      sidebarMenu(
        menuItem(
          "Temperature", 
          tabName = "temp", 
          icon = icon("thermometer-half")
        ),
        menuItem(
          "Other", 
          tabName = "other"
        )
      )
    ),
    dashboardBody(
      tabItems(
        tabItem(
          "temp", 
          plotOutput("plot_temp")
        ),
        tabItem(
          "other", 
          plotOutput("plot_other")
        )
      )
    )
  ),
  server = function(input, output, session) {
    d_city = reactive({
      d |>
        filter(city %in% input$city)
    })
    
    output$plot_temp = renderPlot({
      d_city() |>
        ggplot(aes(x=time, y=temp)) +
        ggtitle("Temperature") +
        geom_line()
    })
    
    output$plot_other = renderPlot({
      d_city() |>
        ggplot(aes(x=time, y=.data[[input$var]])) +
        ggtitle(input$var) +
        geom_line()
    })
    
  }
)

Demo 07-2 - Dynamic sidebarMenu()

demos/demo07-2.R

library(tidyverse)
library(shiny)
library(shinydashboard)

d = readr::read_csv(here::here("data/weather.csv"))

d_vars = d |>
  select(where(is.numeric)) |>
  names()


shinyApp(
  ui = dashboardPage(
    dashboardHeader(
      title="shinydashboard"
    ),
    dashboardSidebar(
      selectInput(
        "city", "Select a city",
        choices = c("Chicago", "Durham", "Sedona", "New York", "Los Angeles")
      ),
      selectInput(
        "var", "Select a variable",
        choices = d_vars, selected = "humidity"
      ),
      sidebarMenuOutput("menu")
    ),
    dashboardBody(
      tabItems(
        tabItem(
          "temp", 
          plotOutput("plot_temp")
        ),
        tabItem(
          "other", 
          plotOutput("plot_other")
        )
      )
    )
  ),
  server = function(input, output, session) {
    output$menu = renderMenu(
      sidebarMenu(
        menuItem("Temperature", tabName = "temp", icon = icon("thermometer-half")),
        menuItem(input$var, tabName = "other")
      )
    )
    
    d_city = reactive({
      d |>
        filter(city %in% input$city)
    })
    
    output$plot_temp = renderPlot({
      d_city() |>
        ggplot(aes(x=time, y=temp)) +
        ggtitle("Temperature") +
        geom_line()
    })
    
    output$plot_other = renderPlot({
      d_city() |>
        ggplot(aes(x=time, y=.data[[input$var]])) +
        ggtitle(input$var) +
        geom_line()
    })
    
  }
)

Body building blocks

box()

infoBox()


valueBox()

Colors

The color of the various boxes is specified via status or background for box() or color for the others.

Available options include,

shinydashboard:::validStatuses
[1] "primary" "success" "info"    "warning" "danger" 


shinydashboard:::validColors
 [1] "red"        "yellow"     "aqua"       "blue"       "light-blue"
 [6] "green"      "navy"       "teal"       "olive"      "lime"      
[11] "orange"     "fuchsia"    "purple"     "maroon"     "black"     

Body layout

The layout of box elements on a dashboard is controlled by combining fluidRow() and column() (as is standard with regular shiny apps)

  • this layout is based on a page having width of 12 units

  • column() and box() elements take a width argument using these units

Row-based layout

dashboardBody(
  fluidRow(
    box(title = "Box title", ...),
    box(...)
  ),

  fluidRow(
    box(title = "Title 1", ...),
    box(title = "Title 2", ...),
    box(title = "Title 3", ...)
  ),

  fluidRow(
    box(...),
    box(title = "Title 5", ...),
    box(title = "Title 6", ...)
  )
)

Column-based layout

dashboardBody(
  fluidRow(
    column(width = 4,
      box(title = "Box title", ...),
      box(title = "Title 1", ...),
      box(...)
    ),
    column(width = 4,
      box(...),
      box(title = "Title 3", ...),
      box(title = "Title 5", ...)
    ),
    column(width = 4,
      box(title = "Title 2", ...),
      box(title = "Title 6", ...)
    )
  )
)

Mixed layout

dashboardBody(
  fluidRow(
    box(title = "Box title", ...),
    box(...)
  ),
  fluidRow(
    column(width = 4,
      box(title = "Title 1", ...),
      box(...)
    ),
    column(width = 4,
      box(title = "Title 3", ...),
      box(title = "Title 5", ...)
    ),
    column(width = 4,
      box(title = "Title 2", ...),
      box(title = "Title 6", ...)
    )
  )
)

Your turn - Exercise 5

Starting with the app from Demo 5 convert the app to use shinydashboard instead of flexdashboard - we have provided some basic scaffolding shinydashboard code in exercises/ex05.R and the demo code in exercises/ex05.Rmd.

Try to preserve the column-based layout and general proportions (read column widths) of the original.

Since shinydashboard does not have a gauge element you can use a value box for everything - If you’re feeling adventurous try using a flexdashboard gauge in your shinydashboard, what happens?

10:00